El analisis exploratorio para esta pregunta se encuentra acontinuación.
import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
from scipy.cluster.hierarchy import dendrogram, linkage
from sklearn.cluster import AgglomerativeClustering
from matplotlib import pyplot as plt
from sklearn.decomposition import PCA
from sklearn.metrics import silhouette_score
path_to_2015 = "../Data/2015.csv" # Hay que agregar el de cada uno.
df = pd.read_csv(path_to_2015) #nrows=100)
print(df.shape)
df.iloc[10:20]
(1233043, 47)
| cat_periodo | codigo_unico | MRUN | GEN_ALU | FEC_NAC_ALU | rango_edad | anio_ing_carr_ori | sem_ing_carr_ori | anio_ing_carr_act | sem_ing_carr_act | ... | area_conocimiento | cine_f_13_area | cine_f_13_subarea | area_carrera_generica | acreditada_carr | acreditada_inst | acre_inst_desde_hasta | acre_inst_anio | costo_proceso_titulacion | costo_obtencion_titulo_diploma | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 10 | 2015 | I16S27C27J2V1 | NaN | 2 | 198303.0 | 30 a 34 años | 9999 | 1 | 2013.0 | 1.0 | ... | Administración y Comercio | Administración de Empresas y Derecho | Educación Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 |
| 11 | 2015 | I16S27C27J2V1 | NaN | 2 | 198612.0 | 25 a 29 años | 9999 | 1 | 2013.0 | 1.0 | ... | Administración y Comercio | Administración de Empresas y Derecho | Educación Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 |
| 12 | 2015 | I16S27C27J2V1 | NaN | 1 | 198612.0 | 25 a 29 años | 9999 | 1 | 2013.0 | 1.0 | ... | Administración y Comercio | Administración de Empresas y Derecho | Educación Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 |
| 13 | 2015 | I16S27C27J2V1 | NaN | 2 | 198807.0 | 25 a 29 años | 9999 | 1 | 2013.0 | 1.0 | ... | Administración y Comercio | Administración de Empresas y Derecho | Educación Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 |
| 14 | 2015 | I16S27C27J2V1 | NaN | 2 | 198506.0 | 30 a 34 años | 9999 | 1 | 2013.0 | 1.0 | ... | Administración y Comercio | Administración de Empresas y Derecho | Educación Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 |
| 15 | 2015 | I16S27C27J2V1 | NaN | 1 | 198907.0 | 25 a 29 años | 9999 | 1 | 2013.0 | 1.0 | ... | Administración y Comercio | Administración de Empresas y Derecho | Educación Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 |
| 16 | 2015 | I16S27C27J2V1 | NaN | 2 | 198411.0 | 30 a 34 años | 9999 | 1 | 2013.0 | 1.0 | ... | Administración y Comercio | Administración de Empresas y Derecho | Educación Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 |
| 17 | 2015 | I16S27C27J2V1 | NaN | 2 | 198507.0 | 25 a 29 años | 9999 | 1 | 2013.0 | 1.0 | ... | Administración y Comercio | Administración de Empresas y Derecho | Educación Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 |
| 18 | 2015 | I16S27C27J2V1 | NaN | 2 | 197912.0 | 35 a 39 años | 9999 | 1 | 2013.0 | 1.0 | ... | Administración y Comercio | Administración de Empresas y Derecho | Educación Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 |
| 19 | 2015 | I16S27C27J2V1 | NaN | 1 | 196303.0 | 40 y más años | 9999 | 1 | 2013.0 | 1.0 | ... | Administración y Comercio | Administración de Empresas y Derecho | Educación Comercial y Administración | Ingeniería Comercial | NO ACREDITADA | NO ACREDITADA | NaN | NaN | 203500 | 305000 |
10 rows × 47 columns
Es necesario destacar que, a pesar de que el dataset posee abundantes atributos, como ya se dijo en el hito uno, muchos de estos pueden tienen relación directa con otros, agregado a esto, en su gran mayoria las columnas son categoricas y poseen pocas clases (o derechamente son binarias). Afortunadamente, esto se compensa con la cantidad de instancias en el dataset, del orden de millones. Con esto podemos suponer (a priori) una caracterización lo suficientemente funcional.
Seleccionamos las columnas en orden de aparición (selección para la matriz de correlación del hito 1):
rango_edadtipo_inst_2: Clasificación del tipo de instituciónjornadatipo_plan_carr: Distinción dada por el tipo plan que posee la carrera o programa.region_sede: Región de la sede.nivel_carrera_2: Tipo de grado académico entregado por la carrera.requisito_ingreso *¡Eliminada, al no estar en el dataset de cada año!vigencia_carrera *¡Eliminada, al no estar en el dataset de cada año!area_conocimientoacreditada_carr: Situación de acreditación de la carrera o programa informada por la institución al 30 de abril del año del proceso. acreditada_inst: Situación acreditación de institución al 30 de abril del año en proceso.También añadimos nuevos atributos que pueden ser vitales en la caracterización:
anio_ing_carr_ori sem_ing_carr_orianio_ing_carr_actsem_ing_carr_act
(- nomb_inst)
(- nomb_carrera)
(- dur_estudio_carr)
(- dur_proceso_tit)dur_total_carrvalor_matriculavalor_arancelPor lo tanto, nos quedamos con 22 de 47 columas
select_columns = ["rango_edad","tipo_inst_2","jornada","tipo_plan_carr","region_sede","nivel_carrera_2","requisito_ingreso", \
"vigencia_carrera","area_conocimiento","acreditada_carr","acreditada_inst","anio_ing_carr_ori","sem_ing_carr_ori", \
"anio_ing_carr_act","sem_ing_carr_act",\
"dur_total_carr", \
"valor_matricula","valor_arancel"]
select = df.loc[:, select_columns]
# Saqué "nomb_inst", "nomb_carrera", "dur_estudio_carr","dur_proceso_tit"
for column in select.select_dtypes('object'):
uniques = select[column].unique()
print(f"Valores unicos de {str(column)}: ", uniques)
Valores unicos de rango_edad: ['20 a 24 años' '15 a 19 años' '35 a 39 años' '25 a 29 años' '30 a 34 años' '40 y más años' nan] Valores unicos de tipo_inst_2: ['Universidades Privadas' 'Universidades CRUCH' 'Institutos Profesionales' 'Centros de Formación Técnica'] Valores unicos de jornada: ['Diurno' 'Vespertino' 'A Distancia' 'Otro' 'Semipresencial'] Valores unicos de tipo_plan_carr: ['Plan Regular' 'Plan Regular de Continuidad' 'Plan Especial'] Valores unicos de region_sede: ['Metropolitana' 'Coquimbo' 'Tarapacá' 'Arica y Parinacota' 'Valparaíso' 'Ñuble' 'Antofagasta' 'Atacama' 'Biobío' "Lib. Gral B. O'Higgins" 'La Araucanía' 'Maule' 'Los Lagos' 'Magallanes' 'Los Ríos' 'Aysén'] Valores unicos de nivel_carrera_2: ['Carreras Profesionales' 'Carreras Técnicas' 'Magister' 'Postítulo' 'Doctorado'] Valores unicos de requisito_ingreso: ['Educación Media' 'Licenciatura' nan 'Título Profesional' 'Técnico de Nivel Superior' 'Magíster' 'Especialidad Médica u Odontológica' 'Plan Común' 'Ciclo Básico' 'Postítulo' 'Bachillerato'] Valores unicos de vigencia_carrera: ['VIGENTE CON ALUMNOS NUEVOS' 'VIGENTE SIN ALUMNOS NUEVOS'] Valores unicos de area_conocimiento: ['Ciencias Sociales' 'Administración y Comercio' 'Arte y Arquitectura' 'Tecnología' 'Salud' 'Ciencias Básicas' 'Agropecuaria' 'Educación' 'Humanidades' 'Derecho' 'Sin área definida'] Valores unicos de acreditada_carr: ['NO ACREDITADA' 'ACREDITADA'] Valores unicos de acreditada_inst: ['ACREDITADA' 'NO ACREDITADA']
Para las columnas con variables categoricas ordinales, se tokeniza de igual manera: en orden. Para columnas categoricas nominales, se tokeniza de forma aleatoria.
Ordinales:
Se creará un diccionario para cada atributo, con sus clases y codificaciones.
all_dict = {}
for column in select.select_dtypes('object'):
all_dict[column] = {value:i+1 for i, value in enumerate(select[column].unique()) if value is not np.nan}
print(all_dict)
all_dict["rango_edad"] = {'15 a 19 años':1,'20 a 24 años':2, '35 a 39 años':3, '25 a 29 años':4, '30 a 34 años':5, '40 y más años':6}
all_dict["nivel_carrera_2"] = {'Carreras Técnicas':1, 'Carreras Profesionales':2, 'Magister':3, 'Postítulo':4, 'Doctorado':5}
all_dict["acreditada_carr"] = {"NO ACREDITADA":0, "ACREDITADA":1}
all_dict["acreditada_inst"] = {"NO ACREDITADA":0, "ACREDITADA":1}
{'rango_edad': {'20 a 24 años': 1, '15 a 19 años': 2, '35 a 39 años': 3, '25 a 29 años': 4, '30 a 34 años': 5, '40 y más años': 6}, 'tipo_inst_2': {'Universidades Privadas': 1, 'Universidades CRUCH': 2, 'Institutos Profesionales': 3, 'Centros de Formación Técnica': 4}, 'jornada': {'Diurno': 1, 'Vespertino': 2, 'A Distancia': 3, 'Otro': 4, 'Semipresencial': 5}, 'tipo_plan_carr': {'Plan Regular': 1, 'Plan Regular de Continuidad': 2, 'Plan Especial': 3}, 'region_sede': {'Metropolitana': 1, 'Coquimbo': 2, 'Tarapacá': 3, 'Arica y Parinacota': 4, 'Valparaíso': 5, 'Ñuble': 6, 'Antofagasta': 7, 'Atacama': 8, 'Biobío': 9, "Lib. Gral B. O'Higgins": 10, 'La Araucanía': 11, 'Maule': 12, 'Los Lagos': 13, 'Magallanes': 14, 'Los Ríos': 15, 'Aysén': 16}, 'nivel_carrera_2': {'Carreras Profesionales': 1, 'Carreras Técnicas': 2, 'Magister': 3, 'Postítulo': 4, 'Doctorado': 5}, 'requisito_ingreso': {'Educación Media': 1, 'Licenciatura': 2, 'Título Profesional': 4, 'Técnico de Nivel Superior': 5, 'Magíster': 6, 'Especialidad Médica u Odontológica': 7, 'Plan Común': 8, 'Ciclo Básico': 9, 'Postítulo': 10, 'Bachillerato': 11}, 'vigencia_carrera': {'VIGENTE CON ALUMNOS NUEVOS': 1, 'VIGENTE SIN ALUMNOS NUEVOS': 2}, 'area_conocimiento': {'Ciencias Sociales': 1, 'Administración y Comercio': 2, 'Arte y Arquitectura': 3, 'Tecnología': 4, 'Salud': 5, 'Ciencias Básicas': 6, 'Agropecuaria': 7, 'Educación': 8, 'Humanidades': 9, 'Derecho': 10, 'Sin área definida': 11}, 'acreditada_carr': {'NO ACREDITADA': 1, 'ACREDITADA': 2}, 'acreditada_inst': {'ACREDITADA': 1, 'NO ACREDITADA': 2}}
for attribute in all_dict:
select[attribute] = select[attribute].map(all_dict[attribute])
select
| rango_edad | tipo_inst_2 | jornada | tipo_plan_carr | region_sede | nivel_carrera_2 | requisito_ingreso | vigencia_carrera | area_conocimiento | acreditada_carr | acreditada_inst | anio_ing_carr_ori | sem_ing_carr_ori | anio_ing_carr_act | sem_ing_carr_act | dur_total_carr | valor_matricula | valor_arancel | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2.0 | 1 | 1 | 1 | 1 | 2 | 1.0 | 1 | 1 | 0 | 1 | 2015 | 1 | NaN | NaN | 8 | 100000.0 | 3369000.0 |
| 1 | 1.0 | 1 | 2 | 1 | 1 | 2 | 1.0 | 1 | 2 | 1 | 1 | 2015 | 1 | NaN | NaN | 8 | 100000.0 | 2312000.0 |
| 2 | 2.0 | 1 | 1 | 1 | 2 | 2 | 1.0 | 1 | 1 | 0 | 0 | 2015 | 1 | NaN | NaN | 10 | 120000.0 | 2185000.0 |
| 3 | 3.0 | 1 | 2 | 1 | 2 | 2 | 1.0 | 1 | 2 | 0 | 0 | 2015 | 1 | NaN | NaN | 10 | 120000.0 | 1760000.0 |
| 4 | 2.0 | 1 | 1 | 1 | 1 | 2 | 1.0 | 1 | 3 | 0 | 1 | 2015 | 1 | NaN | NaN | 10 | 363900.0 | 3900530.0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 1233038 | 6.0 | 1 | 5 | 1 | 1 | 4 | 4.0 | 2 | 10 | 0 | 1 | 2014 | 1 | NaN | NaN | 1 | 0.0 | 1327500.0 |
| 1233039 | 1.0 | 3 | 2 | 1 | 1 | 1 | 1.0 | 1 | 5 | 0 | 1 | 2015 | 1 | NaN | NaN | 7 | 89900.0 | 1489900.0 |
| 1233040 | 1.0 | 1 | 1 | 1 | 1 | 2 | 1.0 | 1 | 4 | 0 | 1 | 2015 | 1 | NaN | NaN | 10 | 340000.0 | 3590000.0 |
| 1233041 | 3.0 | 2 | 1 | 3 | 3 | 3 | 4.0 | 2 | 6 | 0 | 1 | 2013 | 1 | NaN | NaN | 6 | 150000.0 | 1166666.0 |
| 1233042 | 1.0 | 2 | 1 | 1 | 7 | 2 | 1.0 | 1 | 3 | 0 | 1 | 9998 | 1 | 2014.0 | 1.0 | 12 | 122000.0 | 3209000.0 |
1233043 rows × 18 columns
select.iloc[:,:-2] = select.iloc[:,:-2].convert_dtypes(np.int32)
dummies = pd.get_dummies(select, prefix=select_columns[:-2], columns=select_columns[:-2])
dummies
| valor_matricula | valor_arancel | rango_edad_1 | rango_edad_2 | rango_edad_3 | rango_edad_4 | rango_edad_5 | rango_edad_6 | tipo_inst_2_1 | tipo_inst_2_2 | ... | dur_total_carr_8 | dur_total_carr_9 | dur_total_carr_10 | dur_total_carr_11 | dur_total_carr_12 | dur_total_carr_13 | dur_total_carr_14 | dur_total_carr_16 | dur_total_carr_20 | dur_total_carr_24 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 100000.0 | 3369000.0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | ... | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 100000.0 | 2312000.0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | ... | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 120000.0 | 2185000.0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | ... | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 3 | 120000.0 | 1760000.0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | ... | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 4 | 363900.0 | 3900530.0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | ... | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 1233038 | 0.0 | 1327500.0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1233039 | 89900.0 | 1489900.0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1233040 | 340000.0 | 3590000.0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | ... | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1233041 | 150000.0 | 1166666.0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1233042 | 122000.0 | 3209000.0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | ... | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
1233043 rows × 159 columns
height = 10
ward = linkage(dummies.iloc[:1000,2:], method="ward")
fig, ax = plt.subplots(1, 1, figsize=(24,7))
dendrogram(ward, ax=ax)
plt.grid()
plt.title("Linkage: ward")
plt.axhline(y=height, color='r', linestyle='--')
plt.show()
complete = linkage(dummies.iloc[:1000,2:], method="complete")
fig, ax = plt.subplots(1, 1, figsize=(24,7))
dendrogram(complete, ax=ax)
plt.grid()
plt.title("Linkage: ward")
plt.axhline(y=4, color='r', linestyle='--')
plt.show()
Vemos que los clusters estan mejor demarcados por el método ward de clustering Jerárquico, por lo tanto, se decide ocupar para el resto del experimento.
Notamos que, por la naturaleza de las instancias; desglosadas en un One-hot general, los métodos K-means o DBSCAN no podrían ser muy efectivos caracterizando el dataset.
used = 10000 # len(dummies)
Podemos reconocer una leve estructura de cluster en los datos, para el espacio One-Hot. En el caso del método PCA aplicado al espacio antes mencionado, notamos solapamiento entre clusters, aún así, en el gráfico podemos apreciacar estructuras interantes, las que posiblemente contengas información relevante.
Ahora, probamos aplicar Clustering Juerarquico a la colección de vectores luego de aplicar PCA.
sse_k = []
sse_w = []
total_ = 50
clusters = list(range(1, total_+1))
for k in clusters:
kmeans = KMeans(n_clusters=k).fit(dummies.iloc[:used,2:])
#wards = AgglomerativeClustering(n_clusters=k, linkage="ward").fit(dummies.iloc[:used,2:])
sse_k.append(kmeans.inertia_)
#sse_w.append(wards.affinity)
fig, ax = plt.subplots(1,1, figsize=(30,10))
ax.plot(clusters, sse_k, "o-")
plt.title(f"Metodo del codo de 1 a {total_} clusters")
plt.grid(True)
plt.show()
n_clus = 20
ward = AgglomerativeClustering(n_clusters=n_clus, linkage="ward", distance_threshold=None).fit(dummies.iloc[:used,2:])
print(ward.n_clusters_)
new_space = PCA(n_components=2, random_state=1).fit_transform(dummies.iloc[:used,2:])
plt.scatter(new_space[:, 0], new_space[:, 1], c=ward.labels_)
plt.show()
print("Silhouete del espacio PCA con Clusterning Jerarquico (ward)\t", silhouette_score(new_space, ward.labels_))
print("Silhouette del espacio one-hot con Clusterning Jerarquico (ward)\t", silhouette_score(dummies.iloc[:used,2:], ward.labels_))
20
Silhouete del espacio PCA con Clusterning Jerarquico (ward) -0.05801003812797862 Silhouette del espacio one-hot con Clusterning Jerarquico (ward) 0.05964943994947762
from sklearn.cluster import KMeans
kmean = KMeans(n_clusters=n_clus).fit(dummies.iloc[:used,2:])
new_space = PCA(n_components=2, random_state=1).fit_transform(dummies.iloc[:used,2:])
plt.scatter(new_space[:, 0], new_space[:, 1], c=kmean.labels_)
plt.show()
print("Silhouete del espacio PCA con KMeans Clustering\t", silhouette_score(new_space, kmean.labels_))
print("Silhouete del espacio One-hot con KMeans Clustering\t", silhouette_score(dummies.iloc[:used,2:], kmean.labels_))
Silhouete del espacio PCA con KMeans Clustering 0.023934520346331697 Silhouete del espacio One-hot con KMeans Clustering 0.09104361600059412
from sklearn.neighbors import NearestNeighbors
import numpy as np
nbrs = NearestNeighbors(n_neighbors=3).fit(dummies.iloc[:used,2:])
distances, indices = nbrs.kneighbors(dummies.iloc[:used,2:])
y_ = 0.37
distances = np.sort(distances, axis=0)
distances = distances[:,1]
plt.axhline(y=y_, color='r', linestyle='--') #Ajuste el valor para "y" en esta línea
plt.plot(distances)
plt.show()
new_space = PCA(n_components=2, random_state=1).fit_transform(dummies.iloc[:used,2:])
nbrs = NearestNeighbors(n_neighbors=3).fit(new_space)
distances, indices = nbrs.kneighbors(new_space)
y_ = 0.045
distances = np.sort(distances, axis=0)
distances = distances[:,1]
plt.axhline(y=y_, color='r', linestyle='--') #Ajuste el valor para "y" en esta línea
plt.plot(distances)
plt.show()
Imposible establecer mediante el "método de la rodilla" un valor óptimo para epsilon. Esto de igual forma podría indicar que no se establecen cluster de la forma en que DBSCAN los establece.
El segundo gráfico es no concluyente, al aplicarse a una colección de vectores productos del PCA.
from sklearn.cluster import DBSCAN
dbscan = DBSCAN(eps=1.5, min_samples=2).fit(dummies.iloc[:used,2:])
new_space = PCA(n_components=2, random_state=1).fit_transform(dummies.iloc[:used,2:])
plt.scatter(new_space[:, 0], new_space[:, 1], c=dbscan.labels_)
plt.show()
print("Silhouete del espacio PCA con DBSCAN Clustering\t", silhouette_score(new_space, dbscan.labels_))
print("Silhouete del espacio One-hot con DBSCAN Clustering\t", silhouette_score(dummies.iloc[:used,2:], dbscan.labels_))
Silhouete del espacio PCA con DBSCAN Clustering -0.7288990506788339 Silhouete del espacio One-hot con DBSCAN Clustering -0.13678011620936573
DBSCAN no es el método de clustering indicado para el problema
import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
from matplotlib import pyplot as plt
from sklearn.decomposition import PCA
from sklearn.metrics import silhouette_score
from sklearn.metrics.pairwise import euclidean_distances
s_columns = ["rango_edad","tipo_inst_2","jornada","tipo_plan_carr","region_sede","nivel_carrera_2","requisito_ingreso", \
"vigencia_carrera","area_conocimiento","acreditada_carr","acreditada_inst","anio_ing_carr_ori","sem_ing_carr_ori", \
"anio_ing_carr_act","sem_ing_carr_act",\
"dur_total_carr", \
"valor_matricula","valor_arancel"]
# Saqué "nomb_inst", "nomb_carrera", "dur_estudio_carr","dur_proceso_tit"
path_to_2015 = "../../Data/2015.csv" # Hay que agregar el de cada uno.
df = pd.read_csv(path_to_2015)
select = df.loc[:, s_columns]
all_dict = {}
for column in select.select_dtypes('object'):
all_dict[column] = {value:i+1 for i, value in enumerate(select[column].unique()) if value is not np.nan}
print(all_dict)
all_dict["rango_edad"] = {'15 a 19 años':1,'20 a 24 años':2, '35 a 39 años':3, '25 a 29 años':4, '30 a 34 años':5, '40 y más años':6}
all_dict["nivel_carrera_2"] = {'Carreras Técnicas':1, 'Carreras Profesionales':2, 'Magister':3, 'Postítulo':4, 'Doctorado':5}
all_dict["acreditada_carr"] = {"NO ACREDITADA":0, "ACREDITADA":1}
all_dict["acreditada_inst"] = {"NO ACREDITADA":0, "ACREDITADA":1}
{'rango_edad': {'20 a 24 años': 1, '15 a 19 años': 2, '35 a 39 años': 3, '25 a 29 años': 4, '30 a 34 años': 5, '40 y más años': 6}, 'tipo_inst_2': {'Universidades Privadas': 1, 'Universidades CRUCH': 2, 'Institutos Profesionales': 3, 'Centros de Formación Técnica': 4}, 'jornada': {'Diurno': 1, 'Vespertino': 2, 'A Distancia': 3, 'Otro': 4, 'Semipresencial': 5}, 'tipo_plan_carr': {'Plan Regular': 1, 'Plan Regular de Continuidad': 2, 'Plan Especial': 3}, 'region_sede': {'Metropolitana': 1, 'Coquimbo': 2, 'Tarapacá': 3, 'Arica y Parinacota': 4, 'Valparaíso': 5, 'Ñuble': 6, 'Antofagasta': 7, 'Atacama': 8, 'Biobío': 9, "Lib. Gral B. O'Higgins": 10, 'La Araucanía': 11, 'Maule': 12, 'Los Lagos': 13, 'Magallanes': 14, 'Los Ríos': 15, 'Aysén': 16}, 'nivel_carrera_2': {'Carreras Profesionales': 1, 'Carreras Técnicas': 2, 'Magister': 3, 'Postítulo': 4, 'Doctorado': 5}, 'requisito_ingreso': {'Educación Media': 1, 'Licenciatura': 2, 'Título Profesional': 4, 'Técnico de Nivel Superior': 5, 'Magíster': 6, 'Especialidad Médica u Odontológica': 7, 'Plan Común': 8, 'Ciclo Básico': 9, 'Postítulo': 10, 'Bachillerato': 11}, 'vigencia_carrera': {'VIGENTE CON ALUMNOS NUEVOS': 1, 'VIGENTE SIN ALUMNOS NUEVOS': 2}, 'area_conocimiento': {'Ciencias Sociales': 1, 'Administración y Comercio': 2, 'Arte y Arquitectura': 3, 'Tecnología': 4, 'Salud': 5, 'Ciencias Básicas': 6, 'Agropecuaria': 7, 'Educación': 8, 'Humanidades': 9, 'Derecho': 10, 'Sin área definida': 11}, 'acreditada_carr': {'NO ACREDITADA': 1, 'ACREDITADA': 2}, 'acreditada_inst': {'ACREDITADA': 1, 'NO ACREDITADA': 2}}
def sim_matrix(features, labels):
useful_labels = labels >= 0
# primero ordenamos los datos en base al cluster que pertencen
indices = np.argsort(labels[useful_labels])
sorted_features = features[useful_labels][indices]
# calculamos las distancias entre todos los puntos
d = euclidean_distances(sorted_features, sorted_features)
return d
def plotproxi(data, model):
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20,5))
fig.suptitle(f"{model.__class__.__name__}")
ax1.scatter(data[:,0], data[:,1], c=model.labels_)
dist = sim_matrix(data, model.labels_)
im = ax2.imshow(dist, cmap="jet")
fig.colorbar(im, ax=ax2)
# Podemos seleccionar un atributo, y ordenar los clusters de acuerdo
# a la cantidad de cierta caracteristica en el atributo.
def right_tag(df, model, n_clusters, col="area_conocimiento", value="Ciencias Básicas"):
indx = all_dict[col][value]
quantities = np.zeros(n_clusters)
for cluster in range(n_clusters):
count = df.loc[model.labels_==cluster,:][col].value_counts()
try: val = count.loc[indx]
except: val = 0
quantities[cluster] = val
neworder = np.argsort(quantities)
model.labels_ = np.array([neworder[label] for label in model.labels_])
#return
used = 10000
n_clus = 20 # Ideal: 20
np.random.seed(10)
n_years = 10
ndims = 2
select_columns = s_columns.copy()
for nn in ['requisito_ingreso', 'vigencia_carrera']:
try: select_columns.remove(nn)
except: pass
try: all_dict.pop(nn)
except: pass
macro_varancel = np.zeros(n_years)
macro_vmatricula = np.zeros(n_years)
macro_areaconocimiento = np.zeros(n_years, dtype='object')
macro_acredcarr = np.zeros(n_years, dtype='object')
centroid_coord = np.zeros((n_years, n_clus, ndims))
for i in range(n_years):
path = f"../../Data/201{i}.csv" # Hay que agregar el de cada uno.
df = pd.read_csv(path, nrows=None)
sample = np.random.choice(len(df), used)
macro_varancel[i] = df["valor_arancel"].mean()
macro_vmatricula[i] = df["valor_matricula"].mean()
macro_acredcarr[i] = df["acreditada_carr"].value_counts().index[0]
macro_areaconocimiento[i] = df["area_conocimiento"].value_counts().index[0]
#Se escoger al azar 'used' número de instancias.
df = df.loc[sample, select_columns]
for attribute in all_dict:
df[attribute] = df[attribute].map(all_dict[attribute])
df.iloc[:,:-2] = df.iloc[:,:-2].convert_dtypes(np.int32)
dumm = pd.get_dummies(df, prefix=select_columns[:-2], columns=select_columns[:-2])
print("n° de instancias: ", len(df))
kmean = KMeans(n_clusters=n_clus).fit(dumm.iloc[:,2:])
print(f"Inercia del año 201{i}", kmean.inertia_)
right_tag(df,kmean,n_clus) # Nuevas labels por contenido.
pca = PCA(n_components=ndims, random_state=1).fit(dumm.iloc[:,2:])
new_space = pca.transform(dumm.iloc[:,2:])
plotproxi(new_space, kmean)
plt.show()
centroid_coord[i, :, :] = pca.transform(kmean.cluster_centers_)
print("n° de instancias usadas: ", used)
print("Silhouete del espacio PCA con KMeans Clustering\t", silhouette_score(new_space, kmean.labels_))
print("Silhouette del espacio one-hot con KMeans Clustering\t", silhouette_score(dumm.iloc[:,2:], kmean.labels_))
print()
for centroid in range(n_clus):
a = centroid_coord[:-1,centroid,:]
print(a[:,0])
b = centroid_coord[1:,centroid,:]
fig, ax = plt.subplots(1, 1, figsize=(10,5))
ax.set_xlim(-1.5,1.5)
ax.set_ylim(-1.5,1.5)
ax.quiver(a[:,0], a[:,1], b[:,0]-a[:,0], b[:,1]-a[:,1], scale_units='xy', angles='xy', scale=1)
plt.show()
n° de instancias: 10000 Inercia del año 2010 42246.498141404394
d:\Proyectos\Python_proyects\Algos-y-Estructuras\lib\site-packages\sklearn\base.py:445: UserWarning: X does not have valid feature names, but PCA was fitted with feature names warnings.warn(
n° de instancias usadas: 10000 Silhouete del espacio PCA con KMeans Clustering -0.011323790682246496 Silhouette del espacio one-hot con KMeans Clustering 0.07710562796231614 n° de instancias: 10000 Inercia del año 2011 43078.168729594174
d:\Proyectos\Python_proyects\Algos-y-Estructuras\lib\site-packages\sklearn\base.py:445: UserWarning: X does not have valid feature names, but PCA was fitted with feature names warnings.warn(
n° de instancias usadas: 10000 Silhouete del espacio PCA con KMeans Clustering 0.035365353341361205 Silhouette del espacio one-hot con KMeans Clustering 0.08149195910951157 n° de instancias: 10000 Inercia del año 2012 43119.22658732171
d:\Proyectos\Python_proyects\Algos-y-Estructuras\lib\site-packages\sklearn\base.py:445: UserWarning: X does not have valid feature names, but PCA was fitted with feature names warnings.warn(
n° de instancias usadas: 10000 Silhouete del espacio PCA con KMeans Clustering 0.044159060968920916 Silhouette del espacio one-hot con KMeans Clustering 0.0806740615210053 n° de instancias: 10000 Inercia del año 2013 41298.96020343526
d:\Proyectos\Python_proyects\Algos-y-Estructuras\lib\site-packages\sklearn\base.py:445: UserWarning: X does not have valid feature names, but PCA was fitted with feature names warnings.warn(
n° de instancias usadas: 10000 Silhouete del espacio PCA con KMeans Clustering 0.08423410575319476 Silhouette del espacio one-hot con KMeans Clustering 0.07936110574473496 n° de instancias: 10000 Inercia del año 2014 42392.22268764166
d:\Proyectos\Python_proyects\Algos-y-Estructuras\lib\site-packages\sklearn\base.py:445: UserWarning: X does not have valid feature names, but PCA was fitted with feature names warnings.warn(
n° de instancias usadas: 10000 Silhouete del espacio PCA con KMeans Clustering 0.050775579927532906 Silhouette del espacio one-hot con KMeans Clustering 0.07704071635341186 n° de instancias: 10000 Inercia del año 2015 42817.43236871694
d:\Proyectos\Python_proyects\Algos-y-Estructuras\lib\site-packages\sklearn\base.py:445: UserWarning: X does not have valid feature names, but PCA was fitted with feature names warnings.warn(
n° de instancias usadas: 10000 Silhouete del espacio PCA con KMeans Clustering 0.07308641876983377 Silhouette del espacio one-hot con KMeans Clustering 0.08014256687992136 n° de instancias: 10000 Inercia del año 2016 41218.06522582609
d:\Proyectos\Python_proyects\Algos-y-Estructuras\lib\site-packages\sklearn\base.py:445: UserWarning: X does not have valid feature names, but PCA was fitted with feature names warnings.warn(
n° de instancias usadas: 10000 Silhouete del espacio PCA con KMeans Clustering -0.00046020981600127317 Silhouette del espacio one-hot con KMeans Clustering 0.08098741960026677
d:\Proyectos\Python_proyects\Algos-y-Estructuras\lib\site-packages\IPython\core\interactiveshell.py:3441: DtypeWarning: Columns (45) have mixed types.Specify dtype option on import or set low_memory=False. exec(code_obj, self.user_global_ns, self.user_ns)
n° de instancias: 10000 Inercia del año 2017 41649.550520311226
d:\Proyectos\Python_proyects\Algos-y-Estructuras\lib\site-packages\sklearn\base.py:445: UserWarning: X does not have valid feature names, but PCA was fitted with feature names warnings.warn(
n° de instancias usadas: 10000 Silhouete del espacio PCA con KMeans Clustering 0.008490222622809905 Silhouette del espacio one-hot con KMeans Clustering 0.07749189237783793 n° de instancias: 10000 Inercia del año 2018 43601.991838357164
d:\Proyectos\Python_proyects\Algos-y-Estructuras\lib\site-packages\sklearn\base.py:445: UserWarning: X does not have valid feature names, but PCA was fitted with feature names warnings.warn(
n° de instancias usadas: 10000 Silhouete del espacio PCA con KMeans Clustering -0.07704703366904166 Silhouette del espacio one-hot con KMeans Clustering 0.09472686254693201 n° de instancias: 10000 Inercia del año 2019 43153.76550594182
d:\Proyectos\Python_proyects\Algos-y-Estructuras\lib\site-packages\sklearn\base.py:445: UserWarning: X does not have valid feature names, but PCA was fitted with feature names warnings.warn(
n° de instancias usadas: 10000 Silhouete del espacio PCA con KMeans Clustering -0.02209234339492895 Silhouette del espacio one-hot con KMeans Clustering 0.10539461166032484 [-0.56090586 0.46647537 0.05576004 -0.54490937 1.34206879 1.44822652 -0.53417596 1.17881153 -0.94789353]
[ 1.02784349 -0.2554861 -1.1744544 -0.58741846 -1.18457996 -0.71092762 -1.06039626 -1.05165799 0.08673461]
[-0.370144 -0.32640219 1.3105458 1.06899868 -0.58819336 -1.19222709 0.520412 0.68806613 1.71537313]
[ 0.26482013 1.49035943 1.56763463 0.7385264 -0.29904413 -1.14625457 0.36842732 0.00611291 -0.34365519]
[-0.2084564 -0.6529721 -0.38165999 -1.28123852 1.43566252 -0.72186626 1.45683682 -1.04053125 -1.06239265]
[ 1.09682865 1.12846722 -0.664198 0.03100433 1.71587925 1.52195892 -0.65934226 -0.83503779 0.3108575 ]
[-0.93881656 0.88156266 0.45285839 0.88158728 -0.15074792 0.8830816 0.67461189 -0.7188154 -0.46876888]
[-0.90538883 -0.87586343 -0.48867238 1.69666577 0.51531942 -0.34652832 -0.25995933 1.72042226 1.08698175]
[-0.62370071 -0.57065819 1.56292595 1.62835078 -0.88999329 0.73385602 -0.88801329 -0.24962205 -0.95880709]
[ 0.07178743 -1.13807864 0.83937124 -0.539472 -0.60403183 -0.68472463 0.47633875 1.10887518 -0.81980939]
[-1.20515172 0.94958959 -0.61835923 -0.35078432 0.43390934 -0.7392483 0.102703 -0.50788219 1.03355117]
[ 1.33045322 0.86180341 0.46511153 0.40828089 -1.14667429 1.60083577 -1.16157997 0.66875221 0.79121097]
[ 1.51209256 -0.03157845 0.81154706 0.53323968 -0.9224241 0.41388736 1.25889658 -0.45173935 -0.71926769]
[-0.07619727 -1.03567636 0.16648358 1.05000175 0.44955145 -0.6730639 1.38976231 -0.73795857 0.86967843]
[ 1.64221478 1.35365691 -0.63511337 -1.13641715 0.58523368 0.37128293 1.31590222 0.50461268 0.62010713]
[-0.61389698 -0.85129377 0.90277892 0.59689238 -0.03325424 -0.73361395 0.1274044 1.3475956 -0.49920625]
[-0.68778427 0.37656518 0.48074717 -0.94055817 0.36551287 0.40896015 -0.6803498 0.61103224 0.84665762]
[-0.31360424 0.59705651 -1.09166133 -0.93124307 1.17954102 0.76774312 0.67159362 0.39430056 0.42779949]
[ 0.48789989 0.43645006 -0.92581466 -0.91617383 1.12767093 -0.15042618 0.32155491 -1.06906747 -0.85525541]
[ 0.41344111 1.65304226 -0.52865946 -0.02965453 0.88813868 0.48599892 0.49592602 0.32615326 -1.02213416]